<script>
export default {
  name: 'NuxtLoading',
  data() {
    return {
      percent:        0,
      show:           false,
      canSucceed:     true,
      reversed:       false,
      skipTimerCount: 0,
      rtl:            false,
      throttle:       200,
      duration:       3000,
      continuous:     false
    };
  },
  computed: {
    left() {
      if (!this.continuous && !this.rtl) {
        return false;
      }

      return this.rtl ? (this.reversed ? '0px' : 'auto') : (!this.reversed ? '0px' : 'auto');
    }
  },
  beforeUnmount() {
    this.clear();
  },
  methods: {
    clear() {
      clearInterval(this._timer);
      clearTimeout(this._throttle);
      this._timer = null;
    },
    start() {
      this.clear();
      this.percent = 0;
      this.reversed = false;
      this.skipTimerCount = 0;
      this.canSucceed = true;

      if (this.throttle) {
        this._throttle = setTimeout(() => this.startTimer(), this.throttle);
      } else {
        this.startTimer();
      }

      return this;
    },
    set(num) {
      this.show = true;
      this.canSucceed = true;
      this.percent = Math.min(100, Math.max(0, Math.floor(num)));

      return this;
    },
    get() {
      return this.percent;
    },
    increase(num) {
      this.percent = Math.min(100, Math.floor(this.percent + num));

      return this;
    },
    decrease(num) {
      this.percent = Math.max(0, Math.floor(this.percent - num));

      return this;
    },
    pause() {
      clearInterval(this._timer);

      return this;
    },
    resume() {
      this.startTimer();

      return this;
    },
    finish() {
      this.percent = this.reversed ? 0 : 100;
      this.hide();

      return this;
    },
    hide() {
      this.clear();
      setTimeout(() => {
        this.show = false;
        this.$nextTick(() => {
          this.percent = 0;
          this.reversed = false;
        });
      }, 500);

      return this;
    },
    fail() {
      this.canSucceed = false;

      return this;
    },
    startTimer() {
      if (!this.show) {
        this.show = true;
      }
      if (typeof this._cut === 'undefined') {
        this._cut = 10000 / Math.floor(this.duration);
      }

      this._timer = setInterval(() => {
        /**
         * When reversing direction skip one timers
         * so 0, 100 are displayed for two iterations
         * also disable css width transitioning
         * which otherwise interferes and shows
         * a jojo effect
         */
        if (this.skipTimerCount > 0) {
          this.skipTimerCount--;

          return;
        }

        if (this.reversed) {
          this.decrease(this._cut);
        } else {
          this.increase(this._cut);
        }

        if (this.continuous) {
          if (this.percent >= 100) {
            this.skipTimerCount = 1;

            this.reversed = !this.reversed;
          } else if (this.percent <= 0) {
            this.skipTimerCount = 1;

            this.reversed = !this.reversed;
          }
        }
      }, 100);
    }
  },
  render(h) {
    let el = h(false);

    if (this.show) {
      el = h('div', {
        staticClass: 'nuxt-progress',
        class:       {
          'nuxt-progress-notransition': this.skipTimerCount > 0,
          'nuxt-progress-failed':       !this.canSucceed
        },
        style: {
          width: `${ this.percent }%`,
          left:  this.left
        }
      });
    }

    return el;
  }
};
</script>
